class VirtualList extends Component {
  constructor(props) {
    super(props);
    this.container = React.createRef(); //容器的引用
    this.extraItemNumber = 2; //额外显示的子项数量
    this.state = {
      containerScrollTop: 0
    };
  }

  //处理容器滚动事件
  handleContainerScroll = e => {
    this.setState({
      containerScrollTop: this.container.current.scrollTop
    });
  };

  //获取虚拟列表
  getVirtualList() {
    const { extraItemNumber, state, props } = this;
    const { containerScrollTop } = state;
    const { itemHeight, children, containerHeight } = props;

    //进行页面计算
    //计算要显示的第一项的 index ，即比滚动高度隐藏的值小一点的
    //比如 容器高度为150，能显示150/30=5 height 30 top 160 = 160/30  约等于 5.34 ， 即有 5.34 个隐藏了，但是半截还是要显示的，所以从第6个开始显示，数组是从0开始，所以第六个的index是 5
    let firstIndex = Math.floor(containerScrollTop / itemHeight);
    //这个同理，多显示一点的项
    let lastIndex = firstIndex + Math.ceil(containerHeight / itemHeight);
    //如果少于更多项，就从0项开始显示
    firstIndex = Math.max(firstIndex - extraItemNumber, 0);
    //如果显示项超出了，就用数组的长度
    lastIndex = Math.min(lastIndex + extraItemNumber, children.length);

    //根据index获取要显示的项
    const arr = [];
    for (let i = firstIndex; i < lastIndex; i++) {
      arr.push(<li key={i}>{children[i]}</li>);
    }
    return {
      arr,
      top: firstIndex * itemHeight
    };
  }

  render() {
    const { itemHeight, containerHeight, children } = this.props;
    const len = children.length;
    const { arr, top } = this.getVirtualList();

    return (
      <div
        style={{ height: `${containerHeight}px` }}
        className="container"
        ref={this.container}
        onScroll={() => this.handleContainerScroll()}
      >
        <div
          className="holder"
          style={{
            height: itemHeight * len + "px"
          }}
        />
        <ul
          className="content"
          style={{
            top: `${top}px`
          }}
        >
          {arr}
        </ul>
      </div>
    );
  }
}
